﻿using System;
using System.Collections;
using System.Collections.Generic;
using Sirenix.OdinInspector;
using UnityEngine;

namespace Snake.Gameplay
{
    [CreateAssetMenu(menuName = "Gameplay/Effect")]
    public class GameplayEffect : SerializedScriptableObject
    {
        public DurationPolicy durationPolicy = DurationPolicy.Infinite;

        [ShowIf(nameof(ShowDurationField))] public float durationMagnitude;

        /// <summary>
        /// 周期，用于持续时间类型
        /// </summary>
        [ShowIf(nameof(ShowDurationAndInfiniteField))] public float period;

        /// <summary>
        /// 计时开始时触发
        /// </summary>
        [ShowIf(nameof(ShowDurationAndInfiniteField))] public bool executePeriodicEffectOnApplication;

        /// <summary>
        /// 属性修改器
        /// </summary>
        public List<GameplayEffectModifier> modifiers = new List<GameplayEffectModifier>();

        /// <summary>
        /// 效果组件
        /// </summary>
        [ValueDropdown(nameof(GetComponents))] [ListDrawerSettings(DraggableItems = false)]
        public List<GameplayEffectComponent> components = new List<GameplayEffectComponent>();

        public string[] gameplayCues = new string[0];

        private bool ShowDurationAndInfiniteField()
        {
            return durationPolicy != DurationPolicy.Instant;
        }

        private bool ShowDurationField()
        {
            return durationPolicy == DurationPolicy.HasDuration;
        }

        private static IEnumerable GetComponents()
        {
            var parent = typeof(GameplayEffectComponent);
            var assembly = parent.Assembly;
            var item = new List<ValueDropdownItem>();
            foreach (var type in assembly.GetTypes())
            {
                if (!type.IsSubclassOf(parent))
                {
                    continue;
                }

                item.Add(new ValueDropdownItem(type.Name, Activator.CreateInstance(type)));
            }

            return item;
        }

        public bool TryGetComponent<T>(out T result)
        {
            result = default;
            foreach (var com in components)
            {
                if (com is not T comT)
                {
                    continue;
                }

                result = comT;
                return true;
            }

            return false;
        }
    }
}